﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;

namespace GBricks.Collections
{
  partial class Comparers
  {
    public static IComparer<T> Reverse<T>(this IComparer<T> comparer) {
      Argument.NotNull(comparer, "comparer");
      Contract.Ensures(Contract.Result<IComparer<T>>() != null);
      return new ReverseComparer<T>(comparer);
    }

    public static IComparer<T> DefaultReverse<T>() {
      Contract.Ensures(Contract.Result<IComparer<T>>() != null);
      return ReverseComparer<T>.Default;
    }

    [Serializable]
    private sealed class ReverseComparer<T> : Comparer<T>
    {
      private static readonly ReverseComparer<T> Instance = new ReverseComparer<T>(Comparer<T>.Default);

      public ReverseComparer(IComparer<T> comparer) {
        Argument.NotNull(comparer, "comparer");
        Original = comparer;
      }

      public static new ReverseComparer<T> Default {
        [DebuggerStepThrough]
        get {
          Contract.Ensures(Contract.Result<ReverseComparer<T>>() != null);
          return Instance;
        }
      }

      private IComparer<T> Original { get; set; }

      [ContractInvariantMethod]
      private void Invariant() {
        Contract.Invariant(Original != null);
      }

      public override int Compare(T x, T y) {
        return Original.Compare(y, x);
      }

      public override bool Equals(object obj) {
        var other = obj as ReverseComparer<T>;
        return other != null && Equals(other.Original, Original);
      }

      public override int GetHashCode() {
        return Original.GetHashCode();
      }
    }
  }
}
